from EmpVoting import NetworkModifier

class WinnerFromIceAlg(NetworkModifier):
    '''
    classdocs
    '''

    def __init__(self, useDynamicFields = False):
        '''
        Constructor
        '''
        self.useDynamicFields = useDynamicFields
        
        
    def Apply(self, network):
        remainingAlternativeSet = set(network.alternativeSet)
        
        iteration = 0
        
        agentUtilDict = {}
        lastAgentUtilDict = {}
        
        minIntrinsicUtil = "unassigned"
        maxIntrinsicUtil = "unassigned"
        #Calculate min and max intrinsic utils        
        for agent in network.agentList:
            for util in agent.intrinsicUtilDict.values():
                if minIntrinsicUtil == "unassigned" or util < minIntrinsicUtil:
                    minIntrinsicUtil = util
                if maxIntrinsicUtil == "unassigned" or util > maxIntrinsicUtil:
                    maxIntrinsicUtil = util
                   
        minSelfLoopWeight = "unassigned"
        #Calculate minSelfLoopWeight
        for agent in network.agentList:
            selfWeight = network.graph[agent][agent]["weight"]
            if minSelfLoopWeight == "unassigned" or selfWeight < minSelfLoopWeight:
                minSelfLoopWeight = selfWeight
            
            
        for alternative in remainingAlternativeSet:
            lastAgentUtilDict[alternative] = {}
            for agent in network.agentList:
                lastAgentUtilDict[alternative][agent] = minIntrinsicUtil
        
        while len(remainingAlternativeSet) > 1:
            iteration += 1
            
            #Social welfare estimate for each alternative
            swEst = {}
            for alternative in remainingAlternativeSet:
                swEst[alternative] = 0
                agentUtilDict[alternative] = {}
                
                for agent in network.agentList:
                    agentUtil = network.graph[agent][agent]["weight"] * agent.intrinsicUtilDict[alternative]
                    
                    outEdgesItter = network.graph.out_edges_iter(agent, True)
                    
                    for source, dest, data in outEdgesItter:
                        if dest != source:
                            agentUtil += data["weight"] * lastAgentUtilDict[alternative][dest]

                    agentUtilDict[alternative][agent] = agentUtil
                    swEst[alternative] += agentUtil
                    
            maxSw = max(swEst.values())
            
            remainingAlternativeSetCopy = set(remainingAlternativeSet)
            for alternative in remainingAlternativeSetCopy:
                if (
                        maxSw - swEst[alternative] >= 
                        2 * len(network.agentList) * 
                        (maxIntrinsicUtil - minIntrinsicUtil) * 
                        (1 - minSelfLoopWeight)**iteration
                    ):
                    remainingAlternativeSet.remove(alternative)
            
            
            lastAgentUtilDict = agentUtilDict
            agentUtilDict = {}
        
        if len(remainingAlternativeSet) != 1:
            print("ICE Error: Remaining alternative set does not contain exactly one node")
        else:
            self.SetNetworkField(network, "bestAlternative", list(remainingAlternativeSet)[0])
        